﻿using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.Serialization.Json;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Transactions;

namespace Utility
{
    public static class Extensions
    {
        public static ObservableCollection<T> Copy<T>(this IEnumerable<T> source)
        {
            ObservableCollection<T> col = new ObservableCollection<T>();
            if (source != null)
            {
                foreach (var item in source)
                {
                    col.Add(item);
                }
            }
            return col;
        }

        public static List<T> CopyToList<T>(this IEnumerable<T> source)
        {
            List<T> col = new List<T>();
            if (source != null)
            {
                foreach (var item in source)
                {
                    col.Add(item);
                }
            }
            return col;
        }

        public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
        {
            foreach (T element in source)
                action(element);
        }

        /// <summary>
        /// 如果类型是Nullable&lt;T&gt;，则返回T，否则返回自身
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static Type GetNonNullableType(this Type type)
        {
            if (IsNullableType(type))
            {
                return type.GetGenericArguments()[0];
            }
            return type;
        }

        /// <summary>
        /// 是否Nullable&lt;T&gt;类型
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static bool IsNullableType(this Type type)
        {
            return type != null && type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>);
        }

        /// <summary>
        /// 获取Lambda表达式的参数表达式
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="S"></typeparam>
        /// <param name="expr"></param>
        /// <returns></returns>
        public static ParameterExpression[] GetParameters<T, S>(this Expression<Func<T, S>> expr)
        {
            return expr.Parameters.ToArray();
        }

        public static void NoLockInvokeDB(Action action)
        {
            var transactionOptions = new System.Transactions.TransactionOptions();
            transactionOptions.IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted;
            using (var transactionScope = new System.Transactions.TransactionScope(System.Transactions.TransactionScopeOption.Required, transactionOptions))
            {
                try
                {
                    action();
                }
                finally
                {
                    transactionScope.Complete();
                }
            }
        }

        public static IEnumerable<T> ToIEnumerableReadUncommitted<T>(this IQueryable<T> query)
        {
            using (var scope = new TransactionScope(
                TransactionScopeOption.Required,
                new TransactionOptions()
                {
                    IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted
                }))
            {
                //string str_temp2 = System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
                IEnumerable<T> toReturn = query.AsEnumerable();
                //string str_temp1 = System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
                //toReturn.Count();
                //string str_temp3 = System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
                scope.Complete();
                return toReturn;
            }
        }

        public static List<T> ToListReadUncommitted<T>(this IQueryable<T> query)
        {
            using (var scope = new TransactionScope(
                TransactionScopeOption.Required,
                new TransactionOptions()
                {
                    IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted
                }))
            {
                List<T> toReturn = query.ToList();
                scope.Complete();
                return toReturn;
            }
        }

        public static int CountReadUncommitted<T>(this IQueryable<T> query)
        {
            using (var scope = new TransactionScope(
                TransactionScopeOption.Required,
                new TransactionOptions()
                {
                    IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted
                }))
            {
                int toReturn = query.Count();
                scope.Complete();
                return toReturn;
            }
        }

        public static IList<T> DataTableToList<T>(this DataTable dt)
        {
            //确认参数有效
            if (dt == null)
                return null;

            IList<T> list = new List<T>();

            for (int i = 0; i < dt.Rows.Count; i++)
            {
                //创建泛型对象
                T _t = Activator.CreateInstance<T>();
                //获取对象所有属性
                PropertyInfo[] propertyInfo = _t.GetType().GetProperties();
                for (int j = 0; j < dt.Columns.Count; j++)
                {
                    foreach (PropertyInfo info in propertyInfo)
                    {
                        //属性名称和列名相同时赋值
                        if (dt.Columns[j].ColumnName.ToUpper().Equals(info.Name.ToUpper()))
                        {
                            if (dt.Rows[i][j] != DBNull.Value)
                            {
                                info.SetValue(_t, dt.Rows[i][j], null);
                            }
                            else
                            {
                                info.SetValue(_t, null, null);
                            }
                            break;
                        }
                    }
                }
                list.Add(_t);
            }
            return list;
        }

        public static ObservableCollection<T> DataTableToOBCollection<T>(this DataTable dt)
        {
            //确认参数有效
            if (dt == null)
                return null;

            ObservableCollection<T> list = new ObservableCollection<T>();

            for (int i = 0; i < dt.Rows.Count; i++)
            {
                //创建泛型对象
                T _t = Activator.CreateInstance<T>();
                //获取对象所有属性
                PropertyInfo[] propertyInfo = _t.GetType().GetProperties();
                for (int j = 0; j < dt.Columns.Count; j++)
                {
                    foreach (PropertyInfo info in propertyInfo)
                    {
                        //属性名称和列名相同时赋值
                        if (dt.Columns[j].ColumnName.ToUpper().Equals(info.Name.ToUpper()))
                        {
                            if (dt.Rows[i][j] != DBNull.Value)
                            {
                                info.SetValue(_t, dt.Rows[i][j], null);
                            }
                            else
                            {
                                info.SetValue(_t, null, null);
                            }
                            break;
                        }
                    }
                }
                list.Add(_t);
            }
            return list;
        }

        public static List<T> JSONStringToList<T>(this string JsonStr)
        {
            //JavaScriptSerializer Serializer = new JavaScriptSerializer();
            List<T> objs = JsonConvert.DeserializeObject<List<T>>(JsonStr);// Serializer.Deserialize<List<T>>(JsonStr);
            return objs;
        }

        public static T JSONStringToObject<T>(this string JsonStr)
        {
            //JavaScriptSerializer Serializer = new JavaScriptSerializer();
            T obj = JsonConvert.DeserializeObject<T>(JsonStr);//Serializer.Deserialize<T>(JsonStr);
            return obj;
        }

        public static T Deserialize<T>(string json)
        {
            T obj = Activator.CreateInstance<T>();
            using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(json)))
            {
                DataContractJsonSerializer serializer = new DataContractJsonSerializer(obj.GetType());
                return (T)serializer.ReadObject(ms);
            }
        }

        public static string SerializerObjectToString<T>(this T obj)
        {
            //JavaScriptSerializer serializer = new JavaScriptSerializer();
            //serializer.MaxJsonLength = 209715200;
            string value = JsonConvert.SerializeObject(obj);// serializer.Serialize(obj);
            value = Regex.Replace(value, @"\\/Date\((\d+)\)\\/", match =>
            {
                DateTime dt = new DateTime(1970, 1, 1);
                dt = dt.AddMilliseconds(long.Parse(match.Groups[1].Value));
                dt = dt.ToLocalTime();
                return dt.ToString("yyyy-MM-dd HH:mm:ss");
            });
            return value;
        }

        public static string SerializerListToString<T>(this List<T> list)
        {
            //JavaScriptSerializer serializer = new JavaScriptSerializer();
            //serializer.MaxJsonLength = 209715200;
            //serializer.RegisterConverters(new JavaScriptConverter[] { new DateTimeConverter() });
            string value = JsonConvert.SerializeObject(list);// serializer.Serialize(list);
            value = Regex.Replace(value, @"\\/Date\((\d+)\)\\/", match =>
            {
                DateTime dt = new DateTime(1970, 1, 1);
                dt = dt.AddMilliseconds(long.Parse(match.Groups[1].Value));
                dt = dt.ToLocalTime();
                return dt.ToString("yyyy-MM-dd HH:mm:ss");
            });
            return value;
        }

        public static string GetMD5(this string data)
        {
            string cl = data;
            string pwd = "";
            MD5 md5 = MD5.Create();//实例化一个md5对像 
            // 加密后是一个字节类型的数组，这里要注意编码UTF8/Unicode等的选择　 
            byte[] s = md5.ComputeHash(Encoding.Default.GetBytes(cl));
            // 通过使用循环，将字节类型的数组转换为字符串，此字符串是常规字符格式化所得 
            for (int i = 0; i < s.Length; i++)
            {
                // 将得到的字符串使用十六进制类型格式。格式后的字符是小写的字母，如果使用大写（X）则格式后的字符是大写字符 
                pwd = pwd + s[i].ToString("X2");
            }
            return pwd;
        }

        /// <summary>
        /// <summary>
        /// 字符串转Unicode
        /// 78   20011WX                      1612输入IC卡用户号，与TCIS系统不一致      
        /// 78   20011WX                      1612\u8f93\u5165IC\u5361\u7528\u6237\u53f7\uff0c\u4e0eTCIS\u7cfb\u7edf\u4e0d\u4e00\u81f4
        /// </summary>
        /// <param name="source">源字符串</param>
        /// <returns>Unicode编码后的字符串</returns>
        public static string String2Unicode(this string source)
        {
            byte[] bytes = Encoding.Unicode.GetBytes(source);
            StringBuilder stringBuilder = new StringBuilder();
            for (int i = 0; i < bytes.Length; i += 2)
            {
                stringBuilder.AppendFormat("\\u{0}{1}", bytes[i + 1].ToString("x").PadLeft(2, '0'), bytes[i].ToString("x").PadLeft(2, '0'));
            }
            return stringBuilder.ToString();
        }

        /// <summary>
        /// Unicode转字符串
        /// 78   20011WX                      1612\u8f93\u5165IC\u5361\u7528\u6237\u53f7\uff0c\u4e0eTCIS\u7cfb\u7edf\u4e0d\u4e00\u81f4        
        /// 78   20011WX                      1612输入IC卡用户号，与TCIS系统不一致      
        /// </summary>
        /// <param name="source">经过Unicode编码的字符串</param>
        /// <returns>正常字符串</returns>
        public static string Unicode2String(this string source)
        {
            return new Regex(@"\\u([0-9A-F]{4})", RegexOptions.IgnoreCase | RegexOptions.Compiled).Replace(
                source, x => string.Empty + Convert.ToChar(Convert.ToUInt16(x.Result("$1"), 16)));
        }

        public static string SubString(string str, int startIndex, int length)
        {
            string result = null;
            try
            {
                byte[] temp = System.Text.Encoding.GetEncoding("GBK").GetBytes(str);
                byte[] arr = new byte[length];
                int count = startIndex + length;
                int k = 0;
                for (int i = startIndex; i < count; i++)
                {
                    arr[k] = temp[i];
                    k++;
                }
                result = System.Text.Encoding.GetEncoding("GBK").GetString(arr).Trim();
                //result = str.Substring(startIndex, length).Trim();
            }
            catch (Exception ex)
            {
                result = null;
                WriteLog.WriteExceptionFile("截取方法SubString异常：" + ex.Message);
            }
            return result;
        }


        ///<summary>
        ///Base64加密
        ///</summary>
        ///<paramname="Message"></param>
        ///<returns></returns>
        public static string Base64Code(this string message)
        {
            byte[] bytes = Encoding.UTF8.GetBytes(message);
            return Convert.ToBase64String(bytes);
        }

        ///<summary>
        ///Base64解密
        ///</summary>
        ///<paramname="Message"></param>
        ///<returns></returns>
        public static string Base64Decode(this string message)
        {
            byte[] bytes = Convert.FromBase64String(message);
            return Encoding.UTF8.GetString(bytes);
        }

        /// <summary>
        /// 把时间戳改成日期格式
        /// </summary>
        /// <param name="timeStamp"></param>
        /// <returns></returns>
        public static DateTime StampToDateTime(string timeStamp)
        {
            DateTime dateTimeStart = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1));
            long lTime = long.Parse(timeStamp + "0000000");
            TimeSpan toNow = new TimeSpan(lTime);

            return dateTimeStart.Add(toNow);
        }

        /// <summary>
        /// 把日期改成10位的Unix时间戳格式
        /// </summary>
        /// <param name="time"></param>
        /// <returns></returns>
        public static int DateTimeToStamp(System.DateTime time)
        {
            System.DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1));
            return (int)(time - startTime).TotalSeconds;
        }

        #region DES 加密解密

        /// <summary>
        /// 进行DES加密。
        /// </summary>
        /// <param name="pToEncrypt">要加密的字符串。</param>
        /// <param name="sKey">密钥，且必须为8位。</param>
        /// <returns>以Base64格式返回的加密字符串。</returns>
        public static string Encrypt(this string pToEncrypt, string sKey)
        {
            using (DESCryptoServiceProvider des = new DESCryptoServiceProvider())
            {
                byte[] inputByteArray = System.Text.Encoding.UTF8.GetBytes(pToEncrypt);
                des.Key = System.Text.ASCIIEncoding.ASCII.GetBytes(sKey);
                des.IV = System.Text.ASCIIEncoding.ASCII.GetBytes(sKey);
                System.IO.MemoryStream ms = new System.IO.MemoryStream();
                using (CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write))
                {
                    cs.Write(inputByteArray, 0, inputByteArray.Length);
                    cs.FlushFinalBlock();
                    cs.Close();
                }
                string str = Convert.ToBase64String(ms.ToArray());
                ms.Close();
                return str;
            }
        }


        // <summary>
        // 进行DES解密。
        // </summary>
        // <param name="pToDecrypt">要解密的以Base64</param>
        // <param name="sKey">密钥，且必须为8位。</param>
        // <returns>已解密的字符串。</returns>
        public static string Decrypt(this string pToDecrypt, string sKey)
        {
            byte[] inputByteArray = Convert.FromBase64String(pToDecrypt);
            using (DESCryptoServiceProvider des = new DESCryptoServiceProvider())
            {
                des.Key = System.Text.ASCIIEncoding.ASCII.GetBytes(sKey);
                des.IV = System.Text.ASCIIEncoding.ASCII.GetBytes(sKey);
                System.IO.MemoryStream ms = new System.IO.MemoryStream();
                using (CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write))
                {
                    cs.Write(inputByteArray, 0, inputByteArray.Length);
                    cs.FlushFinalBlock();
                    cs.Close();
                }
                string str = System.Text.Encoding.UTF8.GetString(ms.ToArray());
                ms.Close();
                return str;
            }
        }

        #endregion
    }
}
